/*******************************************************************************
 * The MOSES project, model based software engineering of networked embedded systems.
 * 
 * Copyright (C) 2010-2013, University of Applied Sciences Wildau,
 * Telematics Research Group, http://www.tm.th-wildau.de/research-group
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses>.
 * 
 * Contributors:
 *     University of Applied Sciences Wildau - initial API and implementation
 * 
 * If you are interested in a commercial license please contact us via 
 * e-mail: ralf.vandenhouten@th-wildau.de.
 ******************************************************************************/
package de.thwildau.tm.moses.examples.nmea.app;

import java.io.DataInput;
import java.io.IOException;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferInputStream;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;

import de.thwildau.tm.moses.examples.nmea.data.Nmea;

/**
 * The {@link NmeaDecoder} decodes {@link Nmea} messages from a ChannelBuffer.
 * 
 * @author Thomas Kistel
 * @version $Revision: 764 $
 */
public class NmeaDecoder extends OneToOneDecoder {

    @Override
    protected Object decode(ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
        ChannelBuffer buf = (ChannelBuffer)msg;
        DataInput in = new ChannelBufferInputStream(buf);
        Nmea nmeaMessage = Nmea.readObject(in);
        
        // validate the checksum
        buf.setIndex(0, buf.capacity());
        byte[] array = new byte[buf.capacity()];
        buf.readBytes(array);
        String line = new String(array);
        Integer checksum = nmeaMessage.getChecksum();
        if(checksum != null) {
            validateChecksum(line, checksum.intValue());
        } else {
            throw new IOException("Invalid data with no checksum: " + line);
        }
        
        return nmeaMessage;
    }

    private static void validateChecksum(String data, int checksum) throws IOException {
        String dataToCheck = data.substring(1, data.indexOf("*"));
        int calcCheckSum = calculateCheckSum(dataToCheck);
        if (calcCheckSum != checksum) {
            String msg = "Invalid checksum " + calcCheckSum + ". Expected " + checksum;
            throw new IOException(msg);
        }
    }

    private static int calculateCheckSum(String str) {
        int cs = 0;
        char[] ca = str.toCharArray();
        cs = ca[0];
        for (int i = 1; i < ca.length; i++)
            cs = cs ^ ca[i]; // XOR
        return cs;
    }
}
